package com.d2.modules.system.dept.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.d2.modules.system.dept.entity.Dept;
import com.d2.modules.system.dept.mapper.IDeptMapper;
import com.d2.modules.system.dept.service.IDeptService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;

@Service
public class DeptServiceImpl extends ServiceImpl<IDeptMapper, Dept> implements IDeptService {
    @Override
    public void add(Dept dept) {
        if(dept.getPid() == null || dept.getPid() == 0){
            dept.setAncestors("0");
            dept.setPid(0L);
        }else {
            Dept pDept = this.getById(dept.getPid());
            dept.setAncestors(pDept.getAncestors() + "," + pDept.getId());
        }
        this.save(dept);

    }

    @Override
    public void deleteById(Long id) {
        Dept dept = getById(id);
        if(dept != null){
            this.removeById(id);
            Dept query = new Dept();
            query.setPid(dept.getId());
            List<Dept> children = this.list(new QueryWrapper<>(query));
            children.forEach(dept1 -> deleteById(dept.getId()));
        }
    }

    @Override
    @Transactional
    public void update(Dept dept){
        Long id = dept.getId();
        Long newPid = dept.getPid();
        if(newPid == null){
            updateById(dept);
            return;
        }

        if(newPid == 0){
            dept.setAncestors("0");
        }
        Dept oldDept = getById(id);
        String oldAncestors = oldDept.getAncestors();
        Long oldPid = oldDept.getPid();
        if(Objects.equals(oldPid, newPid)){
            updateById(dept);
            return;
        }
        String newAncestors;
        if(newPid == 0){
            newAncestors = "0";
        }else {
            Dept newDept = getById(newPid);
            newAncestors = newDept.getAncestors() + "," + newDept.getId();
        }

        dept.setAncestors(newAncestors);

        //获取所有后代
        List<Dept> children = this.baseMapper.selectChildrenById(id);
        for (Dept child: children) {
            String ancestors = child.getAncestors().replaceAll(oldAncestors, newAncestors);
            child.setAncestors(ancestors);
        }
        this.updateBatchById(children);
        updateById(dept);
    }

    @Override
    public List<Dept> tree() {
        return tree(null);
    }

    @Override
    public List<Dept> tree(Long id) {
        return tree(id, -1L);
    }

    @Override
    public List<Dept> tree(Long id, Long exclude) {
        if(id == null){
            id = 0L;
        }
        Dept q = new Dept();
        q.setPid(id);
        LambdaQueryWrapper<Dept> queryWrapper = Wrappers.lambdaQuery(q);
        queryWrapper.notIn(Dept::getId, exclude);
        List<Dept> list = this.list(queryWrapper);
        buildTree(list, exclude);
        return list;
    }

    private void buildTree(List<Dept> list, Long exclude) {
        for (Dept c : list) {
            Dept query = new Dept();
            query.setPid(c.getId());
            LambdaQueryWrapper<Dept> qw = Wrappers.lambdaQuery(query);
            qw.notIn(Dept::getId, exclude);
            List<Dept> list1 = this.list(qw);
            this.buildTree(list1, exclude);
            c.setChildren(list1);
        }
    }

    @Override
    public List<Dept> updateTreeView(Long id) {
        Dept dept = getById(id);
        Long pid = dept.getPid();
        Dept q = new Dept();
        q.setPid(0L);
        QueryWrapper<Dept> queryWrapper = new QueryWrapper<>(q);
        List<Dept> list = this.list(queryWrapper);
        if(pid != 0L) {
            list.forEach(new Consumer<Dept>() {
                @Override
                public void accept(Dept dept) {
                    buildUpdateTreeView(dept, pid, id);
                }
            });
        }
        return list;
    }


    private void buildUpdateTreeView(Dept dept, Long pid, Long id) {
        Dept query = new Dept();
        query.setPid(dept.getId());
        List<Dept> children = list(new QueryWrapper<>(query));
        dept.setChildren(children);
        for (Dept dept1: children) {
            if(Objects.equals(pid, dept.getId())){
                Dept q = new Dept();
                q.setPid(dept.getId());
                LambdaQueryWrapper<Dept> qw = Wrappers.lambdaQuery(q);
                qw.notIn(Dept::getId, id);
                dept1.setChildren(list(qw));
            }else {
                buildUpdateTreeView(dept1, pid, id);
            }
        }
    }
}
